﻿/********************************************************************
	文件:	SphereShape.cs
	作者:	Pangdudu
	日期:	2021/02/24
	描述:	球的形状
    球体坐标转直角坐标:https://zh.wikipedia.org/wiki/%E7%90%83%E5%BA%A7%E6%A8%99%E7%B3%BB
*********************************************************************/

using System;
using UnityEngine;

namespace ShapeMesh
{
	public class SphereShape : Shape
	{
		private static readonly string _sphereMeshName = "Sphere Mesh";//mesh的名称

		#region private members
		private readonly float _radius;//球的半径
		private readonly int _longitude;//经线的数量
		private readonly int _latitude;//纬线的数量
		#endregion

		#region ctor
		public SphereShape(float radius, int longitude = 24, int latitude = 16, MeshPivot meshPivot = MeshPivot.Center) : base(meshPivot, _sphereMeshName)
		{
			_radius = radius;
			_longitude = longitude;
			_latitude = latitude;

            _vertexOffset = GetVertexOffset();
        }
		#endregion

		#region protected override functions
        /// <summary>
        /// 根据mesh中心点的位置，获得顶点位置的偏移量
        /// </summary>
        /// <returns></returns>
        protected sealed override Vector3 GetVertexOffset()
        {
            return _meshPivot switch
            {
                MeshPivot.Center =>  Vector3.zero,
                MeshPivot.Top => new Vector3(0, _radius, 0),
                MeshPivot.Bottom => new Vector3(0, -_radius, 0),
                MeshPivot.Left => new Vector3(-_radius, 0, 0),
                MeshPivot.Right => new Vector3(_radius, 0, 0),
                MeshPivot.Front => new Vector3(0, 0, _radius),
                MeshPivot.Back => new Vector3(0, 0, -_radius),
                _ => Vector3.zero
            };
        }

        /// <summary>
        /// 获得顶点的数据集合
        /// </summary>
        /// <returns></returns>
        protected override Vector3[] GetVertices()
        {
            var curIndex = 0;
            var arrayLen = (_latitude + 1) * (_longitude + 1);
            var vertices = new Vector3[arrayLen];
            for (var lat = 0; lat <= _latitude; lat++)
            {
                //经线角度的取值范围是0~180度
                var latRad = lat * 1.0f / _latitude * Mathf.PI;
                var latCos = Mathf.Cos(latRad);
                var latSin = Mathf.Sin(latRad);
                for (var lon = 0; lon <= _longitude; lon++)
                {
                    //纬线角度的取值范围是0~360度
                    var lonRad = lon * 1.0f / _longitude * Mathf.PI * 2;//每一圈的最后一个点和第一个点重合(设置UV的坐标)
                    var lonCos = Mathf.Cos(lonRad);
                    var lonSin = Mathf.Sin(lonRad);
                    vertices[curIndex++] = new Vector3(latSin * lonCos, latCos, latSin * lonSin) * _radius - _vertexOffset;
                }
            }
            return vertices;
        }

        /// <summary>
        /// 获得法线方向的数据集合
        /// </summary>
        /// <returns></returns>
        protected override Vector3[] GetNormals()
        {
            var curIndex = 0;
            var vertices = Vertices;//获得当前的顶点
            var normals = new Vector3[vertices.Length];
            foreach (var vertex in vertices)
            {
                normals[curIndex++] = (vertex + _vertexOffset).normalized;
            }
            return normals;
        }

        /// <summary>
        /// 获得三角面顶点的索引
        /// </summary>
        /// <returns></returns>
        protected override int[] GetTriangles()
        {
            var curIndex = 0;
            var arrayLen = _latitude * _longitude * 3 * 2;
            var triangles = new int[arrayLen];
            //侧面
            for (var lat = 0; lat < _latitude; lat++)
            {
                for (var lon = 0; lon < _longitude; lon++)
                {
                    var current = lat * (_longitude + 1) + lon;
                    var next = current + _longitude + 1;

                    triangles[curIndex++] = current;
                    triangles[curIndex++] = current + 1;
                    triangles[curIndex++] = next;

                    triangles[curIndex++] = next;
                    triangles[curIndex++] = current + 1;
                    triangles[curIndex++] = next + 1;
                }
            }
            return triangles;
        }

        /// <summary>
        /// 获得UV坐标的数据集合
        /// </summary>
        /// <returns></returns>
        protected override Vector2[] GetUVs()
        {
            var curIndex = 0;
            var arrayLen = (_latitude + 1) * (_longitude + 1);
            var uvs = new Vector2[arrayLen];
            for (var lat = 0; lat <= _latitude; lat++)
                for (var lon = 0; lon <= _longitude; lon++)
                    uvs[curIndex++] = new Vector2((float)lon / _longitude, 1f - (float)lat / _latitude);
            return uvs;
        }
        #endregion

    }
}